#include "dulinklist.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"


#ifndef null
define null NULL
#endif

/**
 * 功 能：
 *      创建一个链表
 * 参 数：
 *      无
 * 返回值：
 *      成功：操作句柄
 *      失败：NULL
 **/
DLinkList *DLinkList_Create()
{
    TDLinkList *ret = (TDLinkList *)malloc(sizeof(TDLinkList));
    if (ret == null) return NULL;
    
    ret->length = 0;
    ret->header.next = NULL;
    ret->header.prev = NULL;
    ret->slider = NULL;

    return ret;
}

/**
 * 功 能：
 *      销毁一个链表
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：0
 *      失败：-1
 **/
int DLinkList_Destory(DLinkList **list)
{
    if (list != NULL)
    {
        free(*list);
        *list = NULL;
        
        return 0;
    }
    return -1;
}

/**
 * 功 能：
 *      清除一个链表, 使得链表恢复到初始状态
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：0
 *      失败：-1
 **/
int DLinkList_Clear(DLinkList *list)
{
    TDLinkList *slist = (TDLinkList *)list;
    if (slist == NULL) return -1;
    
    slist->length = 0;
    slist->header.next = NULL;
    slist->header.prev = NULL;
    slist->slider = NULL;

    return 0;
}

/**
 * 功 能：
 *      获取链表长度
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：链表的长度
 *      失败：-1
 **/
int DLinkList_Length(DLinkList *list)
{
    TDLinkList *slist = NULL;
    if (list == NULL) return -1;
    
    slist = (TDLinkList *)list;
    
    return slist->length;
}
/**
 * 功 能：
 *      获取指定位置的元素
 * 参 数：
 *      list：要操作的链表
 *      pos ：要获取元素的位置
 * 返回值：
 *      成功：节点的首地址
 *      失败：NULL
 **/
DLinkListNode *DLinkList_Get(DLinkList *list, int pos)
{
    int i = 0;
    TDLinkList *slist = NULL;
    DLinkListNode *current = NULL;
    
    if (pos < 0 || list == NULL) return NULL;
    
    slist = (TDLinkList *)list;
    /* 参数判断并矫正 */ 
    if (pos > slist->length) pos = slist->length;
    // 让辅助指针变量指向链表的头部
    // current = &(slist->header);
    current = (DLinkListNode *)slist;

    while (i < pos && current->next != NULL)
    {
        i++;
        current = current->next;
    }

    return current->next;
}
/**
 * 功 能：
 *      在指定的位置插入一个元素
 * 参 数：
 *      list：要操作的链表
 *      node：要插入的节点
 *      pos ：要插入的位置
 * 返回值：
 *      成功：0
 *      失败：-1
 **/
int DLinkList_Insert(DLinkList *list, DLinkListNode *node, int pos)
{
    int i = 0;
    TDLinkList *slist = NULL;
    /* 参数判断 */
    if (list == NULL || node == NULL || pos < 0)
        return -1;
    
    /* 参数判断并矫正 */
    slist = (TDLinkList *)list;
    
    if (pos > slist->length)
        pos = slist->length;

    /* 下面两个个语句实现的效果一致 */
    // DLinkListNode *current = &(slist->header);
    DLinkListNode *current = (DLinkListNode *)slist;
    DLinkListNode *next = NULL;
    
    i = 0;
    while (i < pos && current->next != NULL)
    {
        i++;
        current = current->next;
    }

    // 记录当前节点的后续节点的信息
    next = current->next;   

    // 让前面的链表链接新的node节点
    current->next = node;
    // 让node链接后续的节点
    node->next = next;
    // 当链表插入第一个节点的时候，需要将特殊处理
    if(next != NULL) next->prev = node;
    
    node->prev = current;

    // 如果是第一次插入元素
    if (slist->length == 0)
        slist->slider = node;

    // 如果是头插法，则current还是指向头部
    // 如果链表是初始的状态，即只有头节点，没有其他的任何业务节点，那么
    // 最后一个节点也是第一个节点，还需要下面的操作吗，你品，你细品。
    if (current == (DLinkListNode *)slist)
        node->prev = NULL;

    // 让长度自加一
    slist->length++;
    
    return 0;
}

/**
 * 功 能：
 *      从指定的位置删除一个元素
 * 参 数：
 *      list：要操作的链表
 *      pos ：要删除元素的位置
 * 返回值：
 *      成功：删除节点的首地址
 *      失败：NULL
 **/
DLinkListNode *DLinkList_Delete(DLinkList *list, int pos)
{
    int i = 0;
    TDLinkList *slist = (TDLinkList *)list;
    DLinkListNode *current = NULL, *ret = NULL, *next = NULL;
    
    if (list == NULL || pos < 0 || slist->length < 1)
        return NULL;

    if (pos > slist->length)
        pos = slist->length;

    // current = &(slist->header);
    current = (DLinkListNode *)slist;

    while (i < pos && current->next != NULL)
    {
        i++;
        current = current->next;
    }

    // 缓存被删除的节点位置
    ret = current->next;
    next = ret->next;

    // 连线，跳过要删除的节点
    current->next = next;
    
    if(next != NULL)
    {
        next->prev = current;
        if( current == (DLinkListNode *)slist)
            next->prev = NULL;
    }

    // 若删除元素为游标所指的元素
    if (slist->slider == ret)
        slist->slider = next;

    // 长度自减一
    slist->length--;

    return ret; //将删除的节点的地址返回，让调用者析构这个内存
}

/**
 * 功 能：
 *      删除一个指定的元素
 * 参 数：
 *      list：要操作的链表
 *      node：要删除元素
 * 返回值：
 *      成功：删除节点的首地址
 *      失败：NULL
 **/
DLinkListNode *DLinkList_DeleteNode(DLinkList *list, DLinkListNode *node)
{
    TDLinkList *slist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    int i = 0;
    
    if (slist == NULL || node == NULL)
        return NULL;

    DLinkListNode *current = (DLinkListNode *)slist;
    // 查找node在链表中的位置
    for (i = 0; i < slist->length; i++)
    {
        if (current->next == node)
        {
            ret = current->next;
            break;
        }
        current = current->next;
    }
    //  如果ret 找到，根据 循环变量 i 去删除节点
    if (ret != NULL)
    {
        DLinkList_Delete(slist, i);
    }

    return ret;
}
/**
 * 功 能：
 *      将游标复位
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：复位之后的游标的值
 *      失败：NULL
 **/
DLinkListNode *DLinkList_Reset(DLinkList *list)
{
    TDLinkList *slist = (TDLinkList *)list;
    
    if (slist == NULL) return NULL;
    
    slist->slider = slist->header.next;

    return slist->slider;
}
/**
 * 功 能：
 *      获取当前游标的值
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：当前游标的值
 *      失败：NULL
 **/
DLinkListNode *DLinkList_Current(DLinkList *list)
{
    TDLinkList *slist = (TDLinkList *)list;
    
    if (slist == NULL) return NULL;

    return slist->slider;
}
/**
 * 功 能：
 *      将游标后移，指向链表中下一个节点
 *      返回当前游标的值
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：当前游标的值
 *      失败：NULL
 **/
DLinkListNode *DLinkList_Next(DLinkList *list)
{
    TDLinkList *slist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;
    
    if (slist == NULL || slist->slider == NULL)
        return NULL;
    
    ret = slist->slider;
    slist->slider = ret->next;
    
    return ret;
}

/**
 * 功 能：
 *      将游标前移，指向链表中上一个节点
 *      返回当前游标的值
 * 参 数：
 *      list：要操作的链表
 * 返回值：
 *      成功：当前游标的值
 *      失败：NULL
 **/
DLinkListNode *DLinkList_Prev(DLinkList *list)
{
    TDLinkList *slist = (TDLinkList *)list;
    DLinkListNode *ret = NULL;

    if (slist == NULL || slist->slider == NULL)
        return NULL;

    ret = slist->slider;
    slist->slider = ret->prev;

    return ret;
}

func_DLinkList fun_DLinkList = {
    DLinkList_Create,
    DLinkList_Destory,
    DLinkList_Clear,
    DLinkList_Length,
    DLinkList_Insert,
    DLinkList_Get,
    DLinkList_Delete,
    DLinkList_DeleteNode,
    DLinkList_Reset,
    DLinkList_Current,
    DLinkList_Next,
    DLinkList_Prev};
